home *** CD-ROM | disk | FTP | other *** search
- {$A+,B-,D+,E+,F-,G+,I+,L+,N-,O-,P-,Q-,R-,S+,T-,V-,X+,Y+}
- {$M 16384,0,32786}
- Program BitMap; { rotates/pans/scales a 256x256 bitmap }
- USES CRT; { by Paul H. Kahler Jan 1994 }
-
- Var SinTable,CosTable: Array[0..255] of integer;
- Sin2Table,Cos2Table: Array[0..255] of integer;
- Map:word; {used as a pointer to the bitmap}
-
- Procedure MakeTables; {Creates sin/cos tables}
- Var direction:integer;
- angle:real;
- begin
- For Direction:=0 to 255 do begin {use 256 degrees in circle}
- angle:=Direction;
- angle:=angle*3.14159265/128;
- SinTable[Direction]:=round(Sin(angle)*256);
- CosTable[Direction]:=round(Cos(angle)*256);
- Sin2Table[Direction]:=round(Sin(angle+3.14159265/2)*256*1.2);
- Cos2Table[Direction]:=round(Cos(angle+3.14159265/2)*256*1.2);
- end; { the 1.2 accounts for pixel aspect ratio }
- end;
-
- Procedure DrawScreen(x,y,scale:word; rot:byte);
- var Temp:Longint; {used for intermediate large values}
- ddx,ddy,d2x,d2y:integer;
- i,j:word;
- label hloop,vloop,nodraw;
-
- begin
- { the following 8 lines of code calculate a 'right' and 'down' vector used
- for scanning the source bitmap. I use quotes because these directions
- depend on the rotation. For example, with a rotation, 'right' could mean
- up and to the left while 'down' means up and to the right. Since the
- destination image (screen) is scanned left-right/top-bottom, the bitmap
- needs to be scanned in arbitrary directions to get a rotation. }
-
- Temp:=(CosTable[rot]);Temp:=(Temp*Scale) div 256;
- ddx:=Temp;
- Temp:=(SinTable[rot]);Temp:=(Temp*Scale) div 256;
- ddy:=Temp;
-
- { Different tables are used for the 'down' vector to account for the non-
- square pixels in mode 13h (320x200). The 90 degree difference is built
- into the tables. If you don't like that, then use (rot+64)and255 here
- and take the pi/2 out of CreateTables. To each his own I guess. }
-
- Temp:=(Cos2Table[rot]);Temp:=(Temp*SCALE) div 256;
- d2x:=Temp;
- Temp:=(Sin2Table[rot]);Temp:=(Temp*SCALE) div 256;
- d2y:=Temp;
-
- { Since we want to rotate around the CENTER of the screen and not the upper
- left corner, we need to move 160 pixels 'left' and 100 'up' in the bitmap.}
-
- i:=x-ddx*160-d2x*100; j:=y-ddy*160-d2y*100;
-
- { The following chunk of assembly does the good stuff. It redraws the entire
- screen by scanning left-right/top-bottom on screen while also scanning the
- bitmap in the arbitrary directions determined above. }
-
- ASM
- push ds
- mov ax,[Map] {get segment of bitmap}
- mov ds,ax
- mov ax,$a000 {set es: to video memory}
- mov es,ax
- mov ax,0 {set ds: to upper left corner of}
- mov di,ax {the video memory}
- mov ax,[ddx] {this is just to speed things up later}
- mov si,ax {add ax,si faster than add ax,[ddx] }
- mov cx,200 {Number of rows on Screen}
- vloop:
- push cx
- mov ax,[i] {start scanning the source bitmap}
- mov dx,[j] {at i,j which were calculated above.}
- mov cx,320 {Number of coulumns on screen}
- hloop:
- add ax,si {add the 'right' vector to the current}
- add dx,[ddy] {bitmap coordinates. 8.8 fixed point}
- mov bl,ah { bx = 256*int(y)+int(x) }
- mov bh,dh
- mov bl,[ds:bx] { load a pixel from source }
- mov [es:di],bl { copy it to destination }
- inc di { advance to next destination pixel }
-
- {*** by repeating the above 7 instructions 5 times, and reducing
- the loop count to 64, I have hit 37fps on a 486-33 with a
- fast video card. ***}
-
- loop hloop {End of horizontal loop}
-
- mov ax,d2x { get the 'down' vector }
- mov dx,d2y
-
- { add si,2 } {** uncomment this instr. for extra fun **}
-
- add i,ax { i,j is the starting coords for a line }
- add j,dx { so this moves down one line }
- pop cx { get the row count back and loop }
- loop vloop { End of verticle loop }
- pop ds { Restore the ds }
- end;
- end;
-
- Procedure GraphMode; {start 320x200x256 mode}
- begin
- Asm
- Mov AH,00
- Mov AL,13h
- Int 10h
- end;
- end;
-
- Procedure AllocateMem; {returns a segment pointer for a 64K bitmap}
- label noerror;
- begin
- asm
- mov ah,$48
- mov bx,$1000 { request 64K }
- int $21
- jnc noerror
- mov ax,0000
- noerror: mov Map,ax { The segment pointer goes in Map }
- end;
- If Map=0 then begin
- Writeln('Could not allocate enough memory');
- Writeln('Program ending...');
- Halt;end;
- end;
-
- Procedure GiveBackMem; {returns the memory used for the map to the system}
- begin
- asm
- mov ah,$49
- mov dx,Map
- mov es,dx
- int $21
- end;
- end;
-
- Procedure DrawImage; {draws a test image which shows some limitations.}
-
- { If anyone stuffs in code to load a picture in a standard format
- (ie .gif .bmp etc..) I'd like if you send me a copy. Preferably
- something simple. This will have to do for now. }
-
- Var x,y:integer;
- Begin
- for x:=-32768 to 32767 do mem[Map:x]:=0;
- for y:=0 to 15 do {this just frames the area}
- for x:=y to 255 do begin
- mem[Map:Y*256+x]:=1;
- mem[Map:X*256+y]:=2;
- end;
- for y:=16 to 47 do { this part show Aliasing effects }
- for x:=16 to 255 do mem[Map:Y*256+x]:=2+(x and 1)+(y and 1);
-
- for y:= -50 to 50 do { this draw the circles }
- for x:= round(-sqrt(2500 - y*y)) to round(sqrt(2500 - y*y)) do
- mem[Map:(y+100)*256+x+100]:=5+(X*X+Y*Y) div 100;
-
- for x:=0 to 100 do { These lines also show sampling effects }
- for y:=0 to 8 do
- mem[Map:(Y*2560)+x+41100]:=5;
- end;
-
- Var rot,dr:word;
- x,y,dist,dd:word;
-
- Begin
- AllocateMem;
- DrawImage;
- MakeTables;
- GraphMode;
- x:=32768; y:=0; {this corresponds to (128,0) in fixed point}
- rot:=0; dr:=1; {rotation angle and it's delta}
- dist:=1200; dd:=65534; {distance to bitmap (sort of) and its delta}
- repeat
- DrawScreen(x,y,dist,lo(rot));
- rot:=rot+dr;
- y:=y+128; {slow panning. 1/2 pixel per frame}
- dist:=dist+dd;
- if (dist=2000) or (dist=2) then dd:=-dd;
- if random(150)=1 then dr:=random(7)-3;
- until keypressed;
- GiveBackMem;
- ASM {back to 80x25}
- MOV AX,3
- INT 10h
- END;
- end.